package com.toymate.ai.asr.model.aliyun;

import cn.hutool.core.io.FileUtil;
import com.alibaba.nls.client.AccessToken;
import com.alibaba.nls.client.protocol.InputFormatEnum;
import com.alibaba.nls.client.protocol.NlsClient;
import com.alibaba.nls.client.protocol.SampleRateEnum;
import com.alibaba.nls.client.protocol.asr.SpeechRecognizer;
import com.alibaba.nls.client.protocol.asr.SpeechRecognizerListener;
import com.alibaba.nls.client.protocol.asr.SpeechRecognizerResponse;
import com.toymate.ai.asr.AbstractSttService;
import com.toymate.ai.asr.AsrConfig;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;

/**
 * AliyunSttService
 *
 * @author weirdor (179946422@qq.com)
 * @version v1.0.0
 */
@Slf4j
public class AliyunSttService extends AbstractSttService {

    private static String result;
    private NlsClient client;


    public AliyunSttService(AsrConfig config) {
        this.config = config;
    }

    private static SpeechRecognizerListener getRecognizerListener(String id) {
        SpeechRecognizerListener listener = new SpeechRecognizerListener() {
            // 识别出中间结果.服务端识别出一个字或词时会返回此消息.仅当setEnableIntermediateResult(true)时,才会有此类消息返回
            @Override
            public void onRecognitionResultChanged(SpeechRecognizerResponse response) {
                // 事件名称 RecognitionResultChanged
                System.out.println("name: " + response.getName() +
                        // 状态码 20000000 表示识别成功
                        ", status: " + response.getStatus() +
                        // 一句话识别的中间结果
                        ", result: " + response.getRecognizedText());
            }

            // 识别完毕
            @Override
            public void onRecognitionCompleted(SpeechRecognizerResponse response) {
                // 事件名称 RecognitionCompleted
                System.out.println("name: " + response.getName() +
                        // 状态码 20000000 表示识别成功
                        ", status: " + response.getStatus() +
                        // 一句话识别的完整结果
                        ", result: " + response.getRecognizedText());
                result = response.getRecognizedText();
            }

            @Override
            public void onStarted(SpeechRecognizerResponse speechRecognizerResponse) {

            }

            @Override
            public void onFail(SpeechRecognizerResponse response) {
                //task_id是调用方和服务端通信的唯一标识，当遇到问题时需要提供task_id以便排查。
                System.out.println(
                        "task_id: " + response.getTaskId() +
                                //状态码 20000000 表示识别成功
                                ", status: " + response.getStatus() +
                                //错误信息
                                ", status_text: " + response.getStatusText());
            }
        };
        return listener;
    }

    @Override
    public Optional<String> discern(String id, String filePath) {
        SpeechRecognizer recognizer = null;
        InputStream ins = FileUtil.getInputStream(filePath);
        try {
            String accessKeyId = config.getAliyunAsrConfig().getAccessKeyId();
            String accessKeySecret = config.getAliyunAsrConfig().getAccessKeySecret();
            String appKey = config.getAliyunAsrConfig().getAppKey();
            AccessToken accessToken = new AccessToken(accessKeyId, accessKeySecret);
            try {
                accessToken.apply();
                client = new NlsClient(accessToken.getToken());
                // Step1 创建实例,建立连接
                recognizer = new SpeechRecognizer(client, getRecognizerListener(id));
                recognizer.setAppKey(appKey);
                // 设置音频编码格式
                recognizer.setFormat(InputFormatEnum.WAV);
                // 设置音频采样率
                recognizer.setSampleRate(SampleRateEnum.SAMPLE_RATE_16K);
                // 设置是否返回中间识别结果
                recognizer.setEnableIntermediateResult(false);
                // Step2 此方法将以上参数设置序列化为json发送给服务端,并等待服务端确认
                recognizer.start();
                // Step3 语音数据来自声音文件用此方法,控制发送速率;若语音来自实时录音,不需控制发送速率直接调用 recognizer.sent(ins)即可
                recognizer.send(ins, 6400, 200);
                // Step4 通知服务端语音数据发送完毕,等待服务端处理完成
                recognizer.stop();
                return Optional.ofNullable(result);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            log.info("语音转换文字失败:{}", e.getMessage());
        } finally {
            // Step5 关闭连接
            if (null != recognizer) {
                recognizer.close();
            }
            //关闭连接
            shutdown();
        }
        return Optional.empty();
    }

    public void shutdown() {
        client.shutdown();
    }


}
